#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <direct.h>
#include <windows.h>

// 设置文件模式为二进制
void set_binary_mode(FILE* file) {
#ifdef _WIN32
    _setmode(_fileno(file), _O_BINARY);
#endif
}

// 确保路径中的反斜杠被正确处理
void sanitize_path(char* path) {
    for (char* p = path; *p; p++) {
        if (*p == '/') {
            *p = '\\';  // 将正斜杠转换为反斜杠
        }
    }
}

// RLE解压缩函数
unsigned char* rle_decompress(const unsigned char* compressed, size_t compressed_size, size_t* original_size) {
    if (compressed_size == 0) {
        *original_size = 0;
        return NULL;
    }

    size_t decompressed_size = 0;
    const unsigned char* ptr = compressed;
    const unsigned char* end = compressed + compressed_size;

    while (ptr < end) {
        if (ptr + 1 >= end) break;
        unsigned char count = *ptr++;
        decompressed_size += count;
        ptr++;
    }

    unsigned char* decompressed = (unsigned char*)malloc(decompressed_size);
    if (!decompressed) {
        *original_size = 0;
        return NULL;
    }

    unsigned char* dest = decompressed;
    ptr = compressed;

    while (ptr < end) {
        if (ptr + 1 >= end) break;
        unsigned char count = *ptr++;
        unsigned char byte = *ptr++;
        memset(dest, byte, count);
        dest += count;
    }

    *original_size = decompressed_size;
    return decompressed;
}

// 创建目录（包括所有父目录）
void create_directory(const char* dir_path) {
    char temp[MAX_PATH];
    strncpy(temp, dir_path, MAX_PATH);

    // 逐级创建目录
    for (char* p = temp + 1; *p; p++) {
        if (*p == '\\') {
            *p = '\0';
            CreateDirectoryA(temp, NULL);
            *p = '\\';
        }
    }
    CreateDirectoryA(temp, NULL);
}

int decompress_file(const char* input_path) {
    FILE* input_file = fopen(input_path, "rb");
    if (!input_file) {
        perror("无法打开压缩文件");
        return 1;
    }
    set_binary_mode(input_file);

    // 获取当前工作目录（解压目标根目录）
    char base_dir[MAX_PATH];
    GetCurrentDirectoryA(MAX_PATH, base_dir);
    // 确保目录以斜杠结尾
    if (strlen(base_dir) > 0 && base_dir[strlen(base_dir) - 1] != '\\') {
        strcat(base_dir, "\\");
    }

    printf("开始解压: %s\n", input_path);

    while (!feof(input_file)) {
        int type = fgetc(input_file);
        if (type == EOF) break;

        size_t path_len;
        if (fread(&path_len, sizeof(size_t), 1, input_file) != 1) break;

        char* rel_path = (char*)malloc(path_len + 1);
        if (!rel_path) {
            perror("内存分配失败");
            fclose(input_file);
            return 1;
        }
        if (fread(rel_path, 1, path_len, input_file) != path_len) {
            free(rel_path);
            fclose(input_file);
            return 1;
        }
        rel_path[path_len] = '\0';

        // 确保路径格式正确
        sanitize_path(rel_path);

        // 打印调试信息（包含路径长度和内容）
        printf("解压条目类型: %s, 路径长度: %zu, 路径内容: \"%s\"\n",
            type == 1 ? "文件" : "目录", path_len, rel_path);

        // 构建完整路径（base_dir + rel_path）
        char full_path[MAX_PATH];
        snprintf(full_path, MAX_PATH, "%s%s", base_dir, rel_path);

        if (type == 1) { // 文件条目
            size_t original_size, compressed_size;
            if (fread(&original_size, sizeof(size_t), 1, input_file) != 1 ||
                fread(&compressed_size, sizeof(size_t), 1, input_file) != 1) {
                free(rel_path);
                fclose(input_file);
                return 1;
            }

            unsigned char* compressed_data = (unsigned char*)malloc(compressed_size);
            if (!compressed_data) {
                perror("内存分配失败");
                free(rel_path);
                fclose(input_file);
                return 1;
            }
            if (fread(compressed_data, 1, compressed_size, input_file) != compressed_size) {
                free(compressed_data);
                free(rel_path);
                fclose(input_file);
                return 1;
            }

            size_t actual_original_size;
            unsigned char* original_data = rle_decompress(compressed_data, compressed_size, &actual_original_size);
            free(compressed_data);

            if (!original_data || actual_original_size != original_size) {
                printf("解压缩失败: %s\n", rel_path);
                free(rel_path);
                fclose(input_file);
                return 1;
            }

            // 创建父目录
            char* last_slash = strrchr(full_path, '\\');
            if (last_slash) {
                *last_slash = '\0';
                create_directory(full_path);
                *last_slash = '\\';
            }

            // 写入文件
            printf("创建文件: %s\n", full_path);
            FILE* output_file = fopen(full_path, "wb");
            if (!output_file) {
                printf("无法创建文件: %s\n", full_path);
                free(original_data);
                free(rel_path);
                continue;
            }
            set_binary_mode(output_file);
            fwrite(original_data, 1, original_size, output_file);
            fclose(output_file);
            free(original_data);
        }
        else if (type == 2) { // 目录条目
            // 确保目录路径以斜杠结尾
            if (strlen(full_path) > 0 && full_path[strlen(full_path) - 1] != '\\') {
                strncat(full_path, "\\", MAX_PATH - strlen(full_path) - 1);
            }
            printf("创建目录: %s\n", full_path);
            create_directory(full_path);
        }

        free(rel_path);
    }

    fclose(input_file);
    printf("解压缩完成\n");
    return 0;
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        printf("用法: rleunzip [压缩文件]\n");
        return 1;
    }

    return decompress_file(argv[1]);
}